#include "precomp.h"

using namespace std;

// Macro that calls a COM method returning HRESULT value:
#define HRCALL(a, errmsg) \
do { \
    hr = (a); \
    if (FAILED(hr)) { \
        printf( "%s:%d  HRCALL Failed: %s\n  0x%.8x = %s\n", \
                __FILE__, __LINE__, errmsg, hr, #a ); \
        goto clean; \
    } \
} while (0)

// Helper function to create a DOM instance
IXMLDOMDocument * DomFromCOM()
{
   HRESULT hr;
   IXMLDOMDocument *pxmldoc = NULL;

    HRCALL( CoCreateInstance(CLSID_DOMDocument60,
                  NULL,
                  CLSCTX_INPROC_SERVER,
                  __uuidof(IXMLDOMDocument),
                  (void**)&pxmldoc),
                  "Create a new DOMDocument");

    HRCALL( pxmldoc->put_async(VARIANT_FALSE),
            "should never fail");
    HRCALL( pxmldoc->put_validateOnParse(VARIANT_FALSE),
            "should never fail");
    HRCALL( pxmldoc->put_resolveExternals(VARIANT_FALSE),
            "should never fail");

   return pxmldoc;
clean:
   if (pxmldoc)
    {
         pxmldoc->Release();
    }
    return NULL;
}

VARIANT VariantString(BSTR str)
{
    VARIANT var;
    VariantInit(&var);
    V_BSTR(&var) = SysAllocString(str);
    V_VT(&var) = VT_BSTR;
    return var;
}

extern "C" UINT __stdcall VsTestHostConfig(MSIHANDLE hInstall)
{
	USES_CONVERSION;

	IXMLDOMDocument *pXMLDom=NULL;
	IXMLDOMParseError *pXMLErr=NULL;
	IXMLDOMNode * pConfigurationNode = NULL;
	IXMLDOMNodeList * pXMLNodeList = NULL;
	IXMLDOMNode * pXMLNode = NULL;
	IXMLDOMNode * removeChild = NULL;
	IXMLDOMNode * pNode = NULL;

	IXMLDOMElement * pAppSettings = NULL;
	IXMLDOMNode * pAppSettingsNode = NULL;
	IXMLDOMElement * pAdd = NULL;
	IXMLDOMNode * pAddNode = NULL;

	IXMLDOMAttribute * pKey = NULL;
	IXMLDOMAttribute * pValue = NULL;

	IXMLDOMAttribute *pAttribute = NULL;

	long length;
	CComBSTR bstrConfigQuery = "//configuration";
	CComBSTR bstrQuery = "//appSettings";
	CComBSTR CrmServerPath = "crm://";
	BSTR bstr = NULL;
	VARIANT_BOOL status;
	VARIANT var;
	HRESULT hr;

	CComBSTR appSettings = "appSettings";
	CComBSTR add = "add";
	CComBSTR key = "key";
	VARIANT urlKey;
	VARIANT urlKeyVal;
	CComBSTR value = "value";

	_TCHAR *VSTestHostConfig = NULL;
	_TCHAR *CrmServer = NULL;
	DWORD MAX_LEN = 0;

	//Read the location of VSTESTHOST.exe.config file from the MSI package
	MAX_LEN = 0;
	UINT uiStat = MsiGetProperty(hInstall, _TEXT("FILEEXISTS"), _TEXT(""), &MAX_LEN);
	if(ERROR_MORE_DATA == uiStat)
	{
		++MAX_LEN;
		VSTestHostConfig = new _TCHAR[MAX_LEN+1];
		if(VSTestHostConfig)
		{
			uiStat = MsiGetProperty(hInstall, _TEXT("FILEEXISTS"), LPTSTR(VSTestHostConfig), &MAX_LEN);
		}
	}
	
	//Read the crmserver name from the msi package
	MAX_LEN = 0;
	uiStat = MsiGetProperty(hInstall, _TEXT("CRMSERVER"), _TEXT(""), &MAX_LEN);
	if(ERROR_MORE_DATA == uiStat)
	{
		++MAX_LEN;
		CrmServer = new _TCHAR[MAX_LEN];
		if(CrmServer)
		{
			uiStat = MsiGetProperty(hInstall, _TEXT("CRMSERVER"), LPTSTR(CrmServer), &MAX_LEN);
		}
	}

	CoInitialize(NULL);

	pXMLDom = DomFromCOM();
	if (!pXMLDom) goto clean;
		
	urlKey = VariantString(L"urlkey");
	CrmServerPath.Append(LPTSTR(CrmServer));
	CrmServerPath.Append("/");
		
	urlKeyVal = VariantString(CrmServerPath);

	VariantInit(&var);
	V_BSTR(&var) = SysAllocString(T2OLE(VSTestHostConfig));
	V_VT(&var) = VT_BSTR;
	HRCALL(pXMLDom->load(var, &status), "");

	if (status!=VARIANT_TRUE) {
		HRCALL(pXMLDom->get_parseError(&pXMLErr),"");
		HRCALL(pXMLErr->get_reason(&bstr),"");
		printf("Failed to load DOM from VSTestHost.exe.config. %S\n",
			bstr);
		goto clean;
	}

	//Get the node configuration
	HRCALL(pXMLDom->selectSingleNode(bstrConfigQuery,&pConfigurationNode), "select Configuration Node");

	//Get the child nodes of configuration which are appSettings
	HRCALL(pXMLDom->selectNodes(bstrQuery,&pXMLNodeList), "select appSetting Nodes");

	if(pXMLNodeList != NULL)
	{
		// Get the number of nodes
		HRCALL(pXMLNodeList->get_length(&length),"get_length");
	}

	//Go through each of the child node and delete it.
	for(long i = 0 ; i < length; i++)
	{
		// Get the child node
		if(pXMLNode) pXMLNode->Release();
		HRCALL(pXMLNodeList->get_item(i,&pXMLNode), "get_item: ");

		// Delete the child from config node
		HRCALL(pConfigurationNode->removeChild(pXMLNode, &removeChild), " Remove Child: ");
		if(removeChild)
		{
			removeChild->Release();
			removeChild = NULL;
		}
	}

	if(pXMLNodeList)
	{
		pXMLNodeList->Release();
		pXMLNodeList = NULL;
	}
	
	//Add <appSettings> to <configuration>
	HRCALL(pXMLDom->createElement(appSettings,&pAppSettings), "appSettings:");
	HRCALL(pConfigurationNode->appendChild(pAppSettings, &pAppSettingsNode), "");
	if(pAppSettingsNode)
	{
		pAppSettingsNode->Release();
		pAppSettingsNode = NULL;
	}

	//Add <add>
	HRCALL(pXMLDom->createElement(add,&pAdd), "appSettings:");
	HRCALL(pAppSettings->appendChild(pAdd, &pAddNode), "");
	if(pAddNode)
	{
		pAddNode->Release();
		pAddNode = NULL;
	}

	//Create attribute key="urlkey"
	HRCALL(pXMLDom->createAttribute(key,&pKey), "key:");
	HRCALL(pKey->put_value(urlKey), "");

	//Create attribute value="urlkey"
	HRCALL(pXMLDom->createAttribute(value,&pValue), "value:");
	HRCALL(pValue->put_value(urlKeyVal), "");

	// Add Attributes to <add>
	HRCALL(pAdd->setAttributeNode(pKey,&pAttribute), "Add Key Attribute");
	if(pAttribute)
	{
		pAttribute->Release();
		pAttribute = NULL;
	}
	HRCALL(pAdd->setAttributeNode(pValue,&pAttribute), "Add Value Attribute");   
	if(pAttribute)
	{
		pAttribute->Release();
		pAttribute = NULL;
	}
	
	HRCALL(pXMLDom->save(var),"");

	clean:
	if (bstr) SysFreeString(bstr);
	if (&var) VariantClear(&var);
	if (&urlKey) VariantClear(&urlKey);
	if (&urlKeyVal) VariantClear(&urlKeyVal);

	if (pXMLErr) pXMLErr->Release();
	if (pXMLDom) pXMLDom->Release();
	if (pConfigurationNode) pConfigurationNode->Release();
	if (pXMLNodeList) pXMLNodeList->Release();
	if (pXMLNode) pXMLNode->Release();
	if (removeChild) removeChild->Release();
	if (pNode) pNode->Release();
	if (pAppSettings) pAppSettings->Release();
	if (pAppSettingsNode) pAppSettingsNode->Release();
	if (pAdd) pAdd->Release();
	if (pAddNode) pAddNode->Release();
	if (pKey) pKey->Release();
	if (pValue) pValue->Release();
	if (pAttribute) pAttribute->Release();


	CoUninitialize();

	return ERROR_SUCCESS;
}


extern "C" UINT __stdcall WriteToBatch(MSIHANDLE hInstall)
{
	_TCHAR * FileDir = NULL;
	_TCHAR * Organization = NULL;
	_TCHAR * Domain = NULL;
	_TCHAR * UserName = NULL;
	_TCHAR * UserPassword = NULL;
	_TCHAR * CrmUserBase = NULL;
	_TCHAR * CrmUserStart = NULL;
	_TCHAR * CrmUserCount = NULL;
	_TCHAR * CrmServer = NULL;		

	DWORD MAX_LEN = 0;
    ifstream myfile;
	ofstream myfile2;
		
	//Read the Binaries Folder where RunPopulation.cmd exists
	UINT uiStat = MsiGetProperty(hInstall, _TEXT("Binaries"), _TEXT(""), &MAX_LEN);
	if(ERROR_MORE_DATA == uiStat)
	{
		++MAX_LEN;
		FileDir = new _TCHAR[MAX_LEN];
		if(FileDir)
		{
			uiStat = MsiGetProperty(hInstall, _TEXT("Binaries"), LPTSTR(FileDir), &MAX_LEN);
		}
	}

	//Read the value of CRMSERVER
	MAX_LEN = 0;
	uiStat = MsiGetProperty(hInstall, _TEXT("CRMSERVER"), _TEXT(""), &MAX_LEN);
	if(ERROR_MORE_DATA == uiStat)
	{
		++MAX_LEN;
		CrmServer = new _TCHAR[MAX_LEN];
		if(CrmServer)
		{
			uiStat = MsiGetProperty(hInstall, _TEXT("CRMSERVER"), LPTSTR(CrmServer), &MAX_LEN);
		}
	}

	//Read the value of the Organization
	MAX_LEN = 0;
	uiStat = MsiGetProperty(hInstall, _TEXT("ORGANIZATION"), _TEXT(""), &MAX_LEN);
	if(ERROR_MORE_DATA == uiStat)
	{
		++MAX_LEN;
		Organization = new _TCHAR[MAX_LEN];
		if(Organization)
		{
			uiStat = MsiGetProperty(hInstall, _TEXT("ORGANIZATION"), LPTSTR(Organization), &MAX_LEN);
		}
	}

	//Read the value of the Domain in which CRM exists
	MAX_LEN = 0;
	uiStat = MsiGetProperty(hInstall, _TEXT("CRMDOMAIN"), _TEXT(""), &MAX_LEN);
	if(ERROR_MORE_DATA == uiStat)
	{
		++MAX_LEN;
		Domain = new _TCHAR[MAX_LEN];
		if(Domain)
		{
			uiStat = MsiGetProperty(hInstall, _TEXT("CRMDOMAIN"), LPTSTR(Domain), &MAX_LEN);
		}
	}

	//Read the username of the User who installed CRM
	MAX_LEN = 0;
	uiStat = MsiGetProperty(hInstall, _TEXT("RUNASUSERID"), _TEXT(""), &MAX_LEN);
	if(ERROR_MORE_DATA == uiStat)
	{
		++MAX_LEN;
		UserName = new _TCHAR[MAX_LEN];
		if(UserName)
		{
			uiStat = MsiGetProperty(hInstall, _TEXT("RUNASUSERID"), LPTSTR(UserName), &MAX_LEN);
		}
	}

	//Read the password the User who installed CRM
	MAX_LEN = 0;
	uiStat = MsiGetProperty(hInstall, _TEXT("RUNASUSERPWD"), _TEXT(""), &MAX_LEN);
	if(ERROR_MORE_DATA == uiStat)
	{
		++MAX_LEN;
		UserPassword = new _TCHAR[MAX_LEN];
		if(UserPassword)
		{
			uiStat = MsiGetProperty(hInstall, _TEXT("RUNASUSERPWD"), LPTSTR(UserPassword), &MAX_LEN);
		}
	}

	//Read the test users' base name
	MAX_LEN = 0;
	uiStat = MsiGetProperty(hInstall, _TEXT("USERBASE"), _TEXT(""), &MAX_LEN);
	if(ERROR_MORE_DATA == uiStat)
	{
		++MAX_LEN;
		CrmUserBase = new _TCHAR[MAX_LEN];
		if(CrmUserBase)
		{
			uiStat = MsiGetProperty(hInstall, _TEXT("USERBASE"), LPTSTR(CrmUserBase), &MAX_LEN);
		}
	}

	//Read the test Users starting number
	MAX_LEN = 0;
	uiStat = MsiGetProperty(hInstall, _TEXT("USERSTART"), _TEXT(""), &MAX_LEN);
	if(ERROR_MORE_DATA == uiStat)
	{
		++MAX_LEN;
		CrmUserStart = new _TCHAR[MAX_LEN];
		if(CrmUserStart)
		{
			uiStat = MsiGetProperty(hInstall, _TEXT("USERSTART"), LPTSTR(CrmUserStart), &MAX_LEN);
		}
	}

	//Read the Number of test users
	MAX_LEN = 0;
	uiStat = MsiGetProperty(hInstall, _TEXT("USERCOUNT"), _TEXT(""), &MAX_LEN);
	if(ERROR_MORE_DATA == uiStat)
	{
		++MAX_LEN;
		CrmUserCount = new _TCHAR[MAX_LEN];
		if(CrmUserCount)
		{
			uiStat = MsiGetProperty(hInstall, _TEXT("USERCOUNT"), LPTSTR(CrmUserCount), &MAX_LEN);
		}
	}	

	//If we succeeded in reading the value of usercount
	if(_tcscmp (FileDir, _TEXT("")) != 0)
	{	
		//
		//Open RunPopulation.cmd file and read all the lines into a string and close the file
		//
		char FileName[80];
		sprintf_s(FileName, 80, "%SRunPopulation.cmd", FileDir);
		myfile.open(FileName);
		if (myfile.is_open() == 0)
		{
			return ERROR_INSTALL_FAILURE;
		}
		string line;
		string filebuffer;
		while(!myfile.eof())
		{
			getline(myfile,line);
			filebuffer += line + "\n";
		}
		myfile.close();

		//
		// Open the same file again in write mode and write the values read from msi package
		// Then rewrite back the data read from the file previously stored in the buffer
		//
		myfile2.open(FileName);
		char TempStr[80];

		sprintf_s(TempStr, 80, "%S", CrmServer);
		myfile2 << "SET WEBSERVER=" << TempStr << endl;
		
		sprintf_s(TempStr, 80, "%S", Organization);
		myfile2 << "SET ORGANIZATION=" << TempStr << endl;

		sprintf_s(TempStr, 80, "%S", Domain);
		myfile2 << "SET DOMAIN=" << TempStr << endl;

		sprintf_s(TempStr, 80, "%S", UserName);
		myfile2 << "SET USERNAME=" << TempStr << endl;

		sprintf_s(TempStr, 80, "%S", UserPassword);
		myfile2 << "SET PASSWORD=" << TempStr << endl;

		sprintf_s(TempStr, 80, "%S", CrmUserBase);
		myfile2 << "SET CRMUSERBASE=" << TempStr << endl;

		sprintf_s(TempStr, 80, "%S", CrmUserStart);
		myfile2 << "SET CRMUSERSTART=" << TempStr << endl;

		sprintf_s(TempStr, 80, "%S", CrmUserCount);
		myfile2 << "SET CRMUSERCOUNT=" << TempStr << endl << endl;

		myfile2 << filebuffer << endl;
		myfile2.close();
	}

	delete [] FileDir;
	delete [] Organization;
	delete [] Domain;
	delete [] UserName;
	delete [] UserPassword;
	delete [] CrmUserBase;
	delete [] CrmUserStart;
	delete [] CrmUserCount;
	delete [] CrmServer;

	return ERROR_SUCCESS;

}